package com.example.fastshareapp;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Currency;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.app.Application;
import android.content.ComponentName;
import android.content.Intent;
import android.content.SyncAdapterType;
import android.content.pm.ComponentInfo;
import android.util.Log;

/**
 * @author Bin Possible
 * 
 */
/**
 * @author Bin Possible
 * 
 */
public class MainApp extends Application implements Observable {

	public static enum Module {
		NONE, GENERAL, USE, HOST
	}

	private static final String TAG = "FastShareApp.MainApp";
	public static String PACKAGE_NAME;

	public static final String ALLJOYN_ERROR_EVENT = "ALLJOYN_ERROR_EVENT";
	public static final String APPLICATION_QUIT_EVENT = "APPLICATION_QUIT_EVENT";
	public static final String HISTORY_CHANGED_EVENT = "HISTORY_CHANGED_EVENT";
	public static final String HOST_CHANNEL_STATE_CHANGED_EVENT = "HOST_CHANNEL_STATE_CHANGED_EVENT";
	public static final String HOST_INIT_CHANNEL_EVENT = "HOST_INIT_CHANNEL_EVENT";
	public static final String HOST_START_CHANNEL_EVENT = "HOST_START_CHANNEL_EVENT";
	public static final String HOST_STOP_CHANNEL_EVENT = "HOST_STOP_CHANNEL_EVENT";
	public static final String OUTBOUND_CHANGED_EVENT = "OUTBOUND_CHANGED_EVENT";
	public static final String USE_CHANNEL_STATE_CHANGED_EVENT = "USE_CHANNEL_STATE_CHANGED_EVENT";
	public static final String USE_JOIN_CHANNEL_EVENT = "USE_JOIN_CHANNEL_EVENT";
	public static final String USE_LEAVE_CHANNEL_EVENT = "USE_LEAVE_CHANNEL_EVENT";
	public static final String SENDIMAGE_CHANGED_EVENT = "SENDIMAGE_CHANGED_EVENT";
	public static final String SENDIMAGEINFO_CHANGED_EVENT = "SENDIMAGEINFO_CHANGED_EVENT";
	public static final String HISTORY_IMAGE_CHANGED_EVENT = "HISTORY_IMAGE_CHANGED_EVENT";
	public static final String SEND_RECEIVE_IMAGE_ERROR_EVENT = "SEND_RECEIVE_IMAGE_ERROR_EVENT";
	public final int HISTORY_MAX = 20;

	private ApplicationService.BusAttachmentState m_busBusAttachmentState;
	private String m_HostChannelName;
	private ApplicationService.HostChannelState m_HostChannelState;
	private String m_UseChannelName;
	private ApplicationService.UseChannelState m_UseChannelState;
	private String m_errorString;
	private List<String> m_listChannels;
	private ComponentName m_runningServer;
	private List<Observer> m_listObserver;
	private List<String> m_listOutBound;
	private List<String> m_listHistory;
	private Module m_module;

	// /use to send and receive Image
	private List<Image> m_listImage;
	private List<Image> m_listOutBoundImage;
	private List<ImageInfo> m_listImageInfo;

	public void Init() {
		m_busBusAttachmentState = ApplicationService.BusAttachmentState.DISCONNECTED;
		m_HostChannelName = "";
		m_HostChannelState = ApplicationService.HostChannelState.IDLE;
		m_UseChannelName = "";
		m_UseChannelState = ApplicationService.UseChannelState.IDLE;
		m_listChannels = new ArrayList<String>();
		m_runningServer = null;
		m_listObserver = new ArrayList<Observer>();
		m_listOutBound = new ArrayList<String>();
		m_listHistory = new ArrayList<String>();
		setM_listImage(new ArrayList<Image>());
		m_listOutBoundImage = new ArrayList<Image>();
		m_listImageInfo = new ArrayList<ImageInfo>();
		m_module = Module.NONE;

	}

	public synchronized String getM_HostChannelName() {
		return m_HostChannelName;
	}

	public synchronized void setM_HostChannelName(String m_HostChannelName) {
		this.m_HostChannelName = m_HostChannelName;
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
	}

	public synchronized ApplicationService.HostChannelState getM_HostChannelState() {
		return m_HostChannelState;
	}

	public synchronized void setM_HostChannelState(
			ApplicationService.HostChannelState m_HostChannelState) {
		this.m_HostChannelState = m_HostChannelState;
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
	}

	public synchronized String getM_UseChannelName() {
		return m_UseChannelName;
	}

	public synchronized void setM_UseChannelName(String m_UseChannelName) {
		this.m_UseChannelName = m_UseChannelName;
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
	}

	public synchronized ApplicationService.UseChannelState getM_UseChannelState() {
		return m_UseChannelState;
	}

	public synchronized void setM_UseChannelState(
			ApplicationService.UseChannelState m_UseChannelState) {
		this.m_UseChannelState = m_UseChannelState;
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
	}

	public String getM_errorString() {
		return m_errorString;
	}

	public void setM_errorString(String m_errorString) {
		this.m_errorString = m_errorString;
	}

	public synchronized List<String> getM_listChannels() {
		return m_listChannels;
	}

	public synchronized void setM_listChannels(List<String> m_listChannels) {
		this.m_listChannels = m_listChannels;
	}

	public synchronized List<String> getM_listOutBound() {
		return m_listOutBound;
	}

	public synchronized void setM_listOutBound(List<String> m_listOutBound) {
		this.m_listOutBound = m_listOutBound;
	}

	public synchronized String getLastMessage() {
		return m_listHistory.get(m_listHistory.size() - 1);
	}

	public synchronized List<String> getM_listHistory() {
		List<String> temp = new ArrayList<String>(m_listHistory.size());

		for (String message : m_listHistory) {
			temp.add(new String(message));
		}
		return temp;
	}

	public synchronized void setM_listHistory(List<String> m_listHistory) {
		this.m_listHistory = m_listHistory;
	}

	public synchronized ComponentName getM_runningServer() {
		return m_runningServer;
	}

	public synchronized void setM_runningServer(ComponentName m_runningServer) {
		this.m_runningServer = m_runningServer;
	}

	public synchronized Module getM_module() {
		return m_module;
	}

	public synchronized void setM_module(Module m_module) {
		this.m_module = m_module;
	}

	@Override
	public void onCreate() {
		super.onCreate();
		Init();
		PACKAGE_NAME = getApplicationContext().getPackageName();
		Intent intent = new Intent(this, Application.class);
		m_runningServer = startService(intent);

	}

	public void quit() {
		m_runningServer = null;
		notifyObserver(APPLICATION_QUIT_EVENT);

	}

	@Override
	public synchronized void addObserver(Observer o) {
		if (m_listObserver.indexOf(o) < 0) {
			m_listObserver.add(o);
		}
	}

	@Override
	public synchronized void deleteObserver(Observer o) {
		if (m_listObserver.indexOf(o) >= 0) {
			m_listObserver.remove(o);
		}
	}

	public synchronized void addFoundChannel(String name) {
		removeFoundChannel(name);
		m_listChannels.add(name);
	}

	public synchronized void removeFoundChannel(String name) {
		for (Iterator<String> channel = m_listChannels.iterator(); channel
				.hasNext();) {
			String channelName = channel.next();
			if (channelName.equals(name)) {
				channel.remove();
			}
		}
	}

	public synchronized String getOutBoundItem() {
		if (m_listOutBound.isEmpty()) {
			return null;
		} else {
			return m_listOutBound.remove(0);
		}
	}

	public void addHistoryItems(String nickname, String message) {
		if (m_listHistory.size() == 30) {
			m_listHistory.remove(0);
		}
		DateFormat dateFormat = new SimpleDateFormat("HH:mm");
		Date date = new Date();
		m_listHistory.add("[" + dateFormat.format(date) + "] (" + nickname
				+ ") " + message);
		notifyObserver(HISTORY_CHANGED_EVENT);
	}

	public void addInboundtems(String nickname, String message) {
		addHistoryItems(nickname, message);
	}

	public void addOutBoundItems(String message) {
		if (m_listOutBound.size() == 5) {
			m_listOutBound.remove(0);
		}
		m_listOutBound.add(message);
		notifyObserver(OUTBOUND_CHANGED_EVENT);
	}

	public synchronized void initHostChannel() {
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(HOST_INIT_CHANNEL_EVENT);
	}

	public synchronized void hostStartChannel() {
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(HOST_START_CHANNEL_EVENT);
	}

	public synchronized void hostStopChannel() {
		notifyObserver(HOST_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(HOST_STOP_CHANNEL_EVENT);
	}

	public synchronized void localUserMessage(String message) {
		addInboundtems("Me", message);
		if (m_UseChannelState == ApplicationService.UseChannelState.JOINED) {
			addOutBoundItems(message);
		}
	}

	// ///User to Send Image
	public synchronized void localUserImage(Image image) {
		addImageIntoList(image);
		if (m_UseChannelState == ApplicationService.UseChannelState.JOINED) {
			addOutBoundImage(image);
		}
	}

	public synchronized void addOutBoundImage(Image image) {
		if (m_listOutBoundImage.size() == 100) {
			m_listOutBoundImage.remove(0);
		}
		m_listOutBoundImage.add(image);
		notifyObserver(SENDIMAGE_CHANGED_EVENT);
	}

	public synchronized Image getOutBoundImage() {
		if (m_listOutBoundImage.size() == 0) {
			return null;
		}
		return m_listOutBoundImage.remove(0);
	}

	public List<Image> getM_listImage() {
		return m_listImage;
	}

	public void setM_listImage(List<Image> m_listImage) {
		this.m_listImage = m_listImage;
	}

	private ImageInfo m_imageInfo;

	// //--------
	public ImageInfo getM_imageInfo() {
		return m_imageInfo;
	}

	public void setM_imageInfo(ImageInfo m_imageInfo) {
		this.m_imageInfo = m_imageInfo;
	}

	// //--------
	public synchronized ImageInfo getReceivingImageInfo() {
		if (this.m_listImageInfo.size() == 0) {
			return null;
		}
		return this.m_listImageInfo.remove(0);
	}

	public synchronized ImageInfo getFirstImageInfo() {
		if (this.m_listImageInfo.size() == 0) {
			return null;
		}
		return this.m_listImageInfo.get(0);
	}

	private CheckImageReceiving m_chechSending = new CheckImageReceiving();;

	public synchronized void addImageIntoList(Image _image) {
		this.m_listImage.add(_image);
		if (m_listImageInfo.size() != 0) {
			m_chechSending.stop();
			int currentImageReceived = this.m_listImageInfo.get(0)
					.getM_length();
			int count = 0;
			for (Image image : m_listImage) {
				if (this.m_listImageInfo.get(0).getM_name()
						.equals(image.getM_name())) {
					count += 1;
				}
			}
			if (count < currentImageReceived) {
				m_chechSending.start();
			} else {
				notifyObserver(HISTORY_CHANGED_EVENT);
				m_chechSending.stop();
			}
			Log.i(TAG, "receiing image " + count + "----"
					+ _image.getM_data().length);

		}
	}

	public class CheckImageReceiving implements Runnable {
		private Thread backgroundThread;

		public void start() {
			if (backgroundThread == null) {
				backgroundThread = new Thread(this);
				backgroundThread.start();
			}
		}

		public void stop() {
			if (backgroundThread != null) {
				backgroundThread.interrupt();
				backgroundThread = null;
			}
		}

		@Override
		public void run() {
			try {
				Thread.sleep(20000);
				if (getFirstImageInfo() != null) {
					didErrorWhenReceivingImage();
					backgroundThread.interrupt();
				}
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	private void didErrorWhenReceivingImage() {
		Log.i(TAG, "Error ---------- receiing image");
		removeCompletedImage(getFirstImageInfo().getM_name());
		notifyObserver(SEND_RECEIVE_IMAGE_ERROR_EVENT);
	}

	public synchronized List<Image> getReceivingImageList(String name) {
		List<Image> list = new ArrayList<Image>();
		for (Image image : m_listImage) {
			if (name.equals(image.getM_name())) {
				list.add(image);
			}
		}
		return list;
	}

	public synchronized void removeCompletedImage(String name) {
		List<Image> list = new ArrayList<Image>(this.m_listImage);
		for (Image image : list) {
			if (name.equals(image.getM_name())) {
				this.m_listImage.remove(image);
			}
		}
		if (m_listImage.size() == 0) {
			m_listImage = new ArrayList<Image>();
		}
		m_listImageInfo = new ArrayList<ImageInfo>();
	}

	public synchronized void addImageInfo(ImageInfo _imageInfo) {
		if (this.m_listImageInfo.size() == 5) {
			this.m_listImageInfo.remove(0);
		}
		this.m_listImageInfo.add(_imageInfo);
		// notifyObserver(HISTORY_CHANGED_EVENT);
	}

	public synchronized void didSendImageInfo() {
		this.m_listImageInfo.add(m_imageInfo);
		notifyObserver(SENDIMAGEINFO_CHANGED_EVENT);
	}

	// /////
	public synchronized void remoteUserMessage(String nickname, String message) {
		addInboundtems(nickname, message);
	}

	public void notifyObserver(Object obj) {
		for (int i = 0; i < m_listObserver.size(); i++) {
			Observer o = m_listObserver.get(i);
			o.update(this, obj);
		}
	}

	public synchronized void useJoinChannel() {
		clearHistoryList();
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(USE_JOIN_CHANNEL_EVENT);
	}

	public synchronized void useLeaveChannel() {
		notifyObserver(USE_CHANNEL_STATE_CHANGED_EVENT);
		notifyObserver(USE_LEAVE_CHANNEL_EVENT);
	}

	public void clearHistoryList() {
		m_listHistory.clear();
		notifyObserver(HISTORY_CHANGED_EVENT);
	}

	public void chechIn() {
		if (m_runningServer == null) {
			Intent intent = new Intent(this, ApplicationService.class);
			m_runningServer = startService(intent);
		}
	}

	public void manageError(Module module, String error) {
		m_module = module;
		m_errorString = error;
		notifyObserver(ALLJOYN_ERROR_EVENT);
	}

}
